#include <Windows.h>
#include <gdiplus.h>
#include <vector>
#include <cmath>

#include "draw.h"

#pragma comment(lib,"gdiplus")

using namespace Gdiplus;

struct GdipInit
{
	GdipInit()
	{
		GdiplusStartupInput gsi;
		ULONG_PTR token;

		GdiplusStartup(&token, &gsi, nullptr);
	}
} gdip_init;
struct button
{
	RECT region;
	int name;
};

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);
void draw();
void calc();
double dis(Color c1, Color c2);

const int key = 60;

extern int XWINDOW = 300;
extern int YWINDOW = 500;
extern const int XSCREEN = GetSystemMetrics(SM_CXSCREEN);
extern const int YSCREEN = GetSystemMetrics(SM_CYSCREEN);
extern int LEFTWINDOW = 0;
extern int TOPWINDOW = 0;
extern HWND myhwnd = 0;

extern int state = 0;

HDC memDC;
Graphics * graphics;

std::vector<button> buttons;

Bitmap * image;
double scale = 1.0;
Rect mainrc;
POINT startpt;
POINT curpt;
std::vector<Color> colors;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR cmdline, int show)
{
	WNDCLASSEX wc = { 0 };

	wc.cbSize = sizeof(WNDCLASSEX);
	wc.hCursor = LoadCursor(hInstance, IDC_ARROW);
	wc.hIcon = wc.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
	wc.hInstance = hInstance;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = L"Window";

	RegisterClassEx(&wc);

	HWND hwnd = CreateWindowEx(WS_EX_LAYERED | WS_EX_ACCEPTFILES, L"Window", L"PicPix", WS_POPUP, 0, 0, XSCREEN, YSCREEN, nullptr, nullptr, hInstance, nullptr);
	myhwnd = hwnd;

	HDC hdc = GetDC(hwnd);
	memDC = CreateCompatibleDC(hdc);
	BITMAPINFO bmi = { sizeof(bmi),XSCREEN,YSCREEN,1,32, };
	HBITMAP bmp = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, nullptr, nullptr, 0);
	SelectObject(memDC, bmp);
	DeleteObject(bmp);
	graphics = new Graphics(memDC);
	graphics->Clear(0x0);

	UpdateWindow(hwnd);
	ShowWindow(hwnd, show);

	MSG msg;
	BLENDFUNCTION bf = { 0,0,MAXBYTE,AC_SRC_ALPHA, };
	SIZE size = { XSCREEN,YSCREEN };

	do
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			graphics->Clear(0x0);
			draw();
			UpdateLayeredWindow(hwnd, hdc, nullptr, &size, memDC, &POINT(), 0, &bf, ULW_ALPHA);
		}
	} while (msg.message != WM_QUIT);
	/*while (GetMessage(&msg, nullptr, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
		graphics->Clear(0x0);
		draw();
		
		UpdateLayeredWindow(hwnd, hdc, nullptr, &size, memDC, &POINT(), 0, &bf, ULW_ALPHA);
	}*/

	DeleteDC(memDC);
	delete graphics;
	delete image;

	return 0;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
	static int ox, oy;
	static int lastleft, lasttop;

	switch (Message)
	{
	case WM_CREATE:
		buttons.push_back({ {XWINDOW - 50,0,XWINDOW,50},0 });
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	case WM_LBUTTONDOWN:
		{
			POINT pt = { LOWORD(lParam),HIWORD(lParam) };
			RECT rc;
			//response buttons
			if (pt.x >= LEFTWINDOW + XWINDOW - 50 && pt.x <= LEFTWINDOW + XWINDOW && pt.y >= TOPWINDOW && pt.y <= TOPWINDOW + 50)
			{
				DestroyWindow(hwnd);
			}
			if (state == 2)
			{
				if (pt.x >= LEFTWINDOW + 500 && pt.x <= LEFTWINDOW + 550 && pt.y >= TOPWINDOW + 50 && pt.y <= TOPWINDOW + 100)
				{
					state = 1;
					curpt = startpt = { 0,0 };
				}
			}

			if (wParam & MK_CONTROL)
			{
				startpt = pt;
			}
			else
			{
				ox = pt.x;
				oy = pt.y;
				lastleft = LEFTWINDOW;
				lasttop = TOPWINDOW;
			}
		}
		break;
	case WM_MOUSEMOVE:
		{
			int x = LOWORD(lParam);
			int y = HIWORD(lParam);

			if (wParam & MK_LBUTTON)
			{
				if (wParam & MK_CONTROL)
				{
					curpt.x = x;
					curpt.y = y;
				}
				else
				{
					LEFTWINDOW = lastleft + x - ox;
					TOPWINDOW = lasttop + y - oy;
				}
			}
			
		}
		break;
	case WM_LBUTTONUP:
		{
			int x = LOWORD(lParam);
			int y = HIWORD(lParam);

			if (wParam & MK_CONTROL && startpt.x != 0 && startpt.y != 0 && state == 1)
			{
				mainrc.X = min(x, startpt.x) - LEFTWINDOW;
				mainrc.Y = min(y, startpt.y) - TOPWINDOW;
				mainrc.Width = max(x, startpt.x) - min(x, startpt.x);
				mainrc.Height = max(y, startpt.y) - min(y, startpt.y);
				state = 2;
				colors.clear();
				calc();
			}
		}
		break;
	case WM_DROPFILES:
		{
			HDROP drop = (HDROP)(wParam);
			TCHAR file[MAX_PATH] = { 0 };

			DragQueryFile(drop, 0, file, 100);
			image = new Bitmap(file);
			if (image)
			{
				curpt = startpt = { 0,0 };
				XWINDOW = image->GetWidth();
				YWINDOW = image->GetHeight();
				if (XWINDOW > XSCREEN || YWINDOW > YSCREEN)
				{
					scale = min((double)XSCREEN / XWINDOW, (double)YSCREEN / YWINDOW);
				}

				state = 1;
			}
		}
		break;
	case WM_MOUSEWHEEL:
		int zDelta;
		zDelta = GET_WHEEL_DELTA_WPARAM(wParam);
		if (state == 1)
		{
			if (zDelta > 0)
			{
				scale += 0.05;
			}
			else if (zDelta < 0)
			{
				scale -= 0.05;
				if (scale < 0.1)
				{
					scale = 0.1;
				}
			}
			XWINDOW = image->GetWidth()*scale;
			YWINDOW = image->GetHeight()*scale;
		}
	default:
		return DefWindowProc(hwnd, Message, wParam, lParam);
	}

	return 0;
}

void draw()
{
	static Pen pen{ 0xff00b0ff,1 };
	static SolidBrush brush{ 0xff00b0ff };

	switch (state)
	{
	case 0:																//startup page
		draw_background_startup(graphics);
		break;
	case 1:
		graphics->DrawImage(image, LEFTWINDOW, TOPWINDOW, XWINDOW, YWINDOW);
		graphics->DrawRectangle(&pen, startpt.x, startpt.y, curpt.x - startpt.x, curpt.y - startpt.y);
		break;
	case 2:
		graphics->DrawImage(image, LEFTWINDOW, TOPWINDOW, XWINDOW, YWINDOW);
		brush.SetColor(0xff123456);
		graphics->FillRectangle(&brush, max(0, LEFTWINDOW + 50), max(0, TOPWINDOW + 50), 500, 300);
		for (int i = 0; i < colors.size(); i++)
		{
			brush.SetColor(colors[i]);
			graphics->FillRectangle(&brush, LEFTWINDOW + 75 + (i % 14) * 32, TOPWINDOW + 100 + (i / 14) * 32, 32, 32);
		}
		draw_sysbutton2(graphics);
		break;
	}

	draw_sysbutton(graphics);
}

void calc()
{
	Color temp;
	bool flag;

	for (int i = mainrc.X; i <= mainrc.X + mainrc.Width; i++)
	{
		for (int j = mainrc.Y; j <= mainrc.Y + mainrc.Height; j++)
		{
			flag = true;
			image->GetPixel(i / scale, j / scale, &temp);
			for (auto t : colors)
			{
				if (dis(t, temp) < key)
				{
					flag = false;
					break;
				}
			}
			if (flag)
			{
				colors.push_back(temp);
			}
		}
	}
}

double dis(Color c1, Color c2)
{
	return sqrt((c1.GetR() - c2.GetR())*(c1.GetR() - c2.GetR()) + (c1.GetB() - c2.GetB())*(c1.GetB() - c2.GetB()) + (c1.GetG() - c2.GetG())*(c1.GetG() - c2.GetG()));
}